package web.stu.controller;

import cn.hutool.core.util.ObjUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
import web.stu.common.ErrorCode;
import web.stu.config.Result;
import web.stu.exception.BusinessException;
import web.stu.model.dto.user.*;
import web.stu.model.entity.User;
import web.stu.model.enums.UserRoleEnum;
import web.stu.model.vo.UserVO;
import web.stu.service.UserService;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.List;


/**
 * 用户管理控制器
 * 
 * <p>提供用户相关的所有操作，包括用户注册、登录、注销、信息查询和修改等功能。</p>
 * 
 * <p>实现了基于角色的权限控制，不同角色用户可访问的接口不同。</p>
 * 
 * @author 系统开发者
 * @version 1.0
 * @since 2023-01-01
 */
@Slf4j
@RestController
@RequestMapping("/user")
@Api(value = "用户的管理模块", tags = "用户模块")
public class UserController {

    @Resource
    private UserService userService;

    /**
     * 用户登录接口
     * @param loginDTO 登录信息DTO，包含用户名和密码
     * @param request HTTP请求对象，用于获取会话信息
     * @return 包含用户基本信息的Result对象
     * @throws BusinessException 如果用户名或密码错误会抛出异常
     * @apiNote 所有角色均可访问
     */
    @PostMapping("/login")
    @ApiOperation(value = "用户登录", notes = "使用用户名和密码进行登录，返回用户信息和token")
    public Result<UserVO> login(@RequestBody LoginDTO loginDTO, HttpServletRequest request) {
        UserVO userVO = userService.login(loginDTO, request);
        return Result.success(userVO);
    }


    /**
     * 用户注册接口
     * @param registerDTO 注册信息DTO，包含用户名、密码、姓名、角色等信息
     * @return 包含注册用户基本信息的Result对象
     * @throws BusinessException 如果用户名已存在会抛出异常
     * @apiNote 所有角色均可访问
     * @see RegisterDTO
     */
    @PostMapping("/register")
    @ApiOperation(value = "用户注册", notes = "注册新用户，需要提供用户名、密码、姓名和角色等信息")
    public Result<UserVO> register(@RequestBody RegisterDTO registerDTO) {
        UserVO userVO = userService.register(registerDTO);
        return Result.success(userVO);
    }

    /**
     * 获取当前登录用户信息接口
     * @param request HTTP请求对象，用于获取会话信息
     * @return 包含当前用户基本信息的Result对象
     * @throws BusinessException 如果用户未登录会抛出异常
     * @apiNote 所有已登录用户均可访问
     */
    @GetMapping("/current")
    @ApiOperation(value = "获取当前登录用户信息", notes = "根据请求头中的token获取当前登录用户的信息")
    public Result<UserVO> getCurrentLoginUser(HttpServletRequest request) {
        return Result.success(userService.currentLoginUser(request));
    }

    /**
     * 用户注销接口
     * @param request HTTP请求对象，用于获取会话信息
     * @return 包含注销成功信息的Result对象
     * @apiNote 所有已登录用户均可访问
     */
    @GetMapping("/logout")
    @ApiOperation(value = "用户登出", notes = "清除当前用户的登录状态")
    public Result<String> logout(HttpServletRequest request) {
        userService.logout(request);
        return Result.success("退出登录成功");
    }

    /**
     * 根据ID获取用户信息接口
     * @param id 用户ID
     * @param request HTTP请求对象，用于获取会话信息
     * @return 包含用户基本信息的Result对象
     * @throws BusinessException 如果ID为空或用户无权限会抛出异常
     * @apiNote 仅管理员或用户本人可访问
     */
    @GetMapping("/get/{id}")
    @ApiOperation(value = "根据ID获取用户", notes = "根据用户ID获取用户详细信息，仅管理员或用户本人可访问")
    public Result<UserVO> getUserById(@PathVariable("id") Integer id, HttpServletRequest request) {
        // 非空判断
        if (id == null) {
            throw new BusinessException(ErrorCode.PRIMARY_ERROR);
        }
        // 判断是否为管理员或当前用户
        User loginUser = userService.getLoginUser(request);
        if (!userService.isCompareRole(loginUser, UserRoleEnum.ADMIN.getKey()) && !loginUser.getId().equals(id)) {
            throw new BusinessException(ErrorCode.NO_AUTH_ERROR, "仅管理员和自己可用");
        }
        UserVO userVO = userService.getUserById(id, request);
        return Result.success(userVO);
    }

    /**
     * 获取用户分页列表接口
     * @param queryUserDTO 用户查询条件DTO，包含分页参数和查询条件
     * @param request HTTP请求对象，用于获取会话信息
     * @return 包含用户分页列表的Result对象
     * @throws BusinessException 如果用户无权限会抛出异常
     * @apiNote 仅管理员和教师可访问
     */
    @PostMapping("/list")
    @ApiOperation(value = "获取用户分页列表", notes = "根据查询条件获取用户分页列表，仅管理员和教师可访问")
    public Result<Page<UserVO>> getAllUsers(@RequestBody QueryUserDTO queryUserDTO, HttpServletRequest request) {
        // 非空判断
        if (ObjUtil.isEmpty(queryUserDTO)) {
            throw new BusinessException(ErrorCode.PRIMARY_ERROR);
        }
        // 判断是否为管理员或教师
        User loginUser = userService.getLoginUser(request);
        if (!userService.isCompareRole(loginUser, UserRoleEnum.ADMIN.getKey()) && !loginUser.getRole().equals(UserRoleEnum.TEACHER.getValue())) {
            throw new BusinessException(ErrorCode.NO_AUTH_ERROR, "仅管理员和教师可用");
        }
        Page<UserVO> userVOPage = userService.listUsers(queryUserDTO, request);
        return Result.success(userVOPage);
    }

    /**
     * 更新用户信息接口
     * @param updateUserDTO 用户更新信息DTO，包含用户ID和需要更新的字段
     * @param request HTTP请求对象，用于获取会话信息
     * @return 包含更新后用户基本信息的Result对象
     * @throws BusinessException 如果用户无权限或数据验证失败会抛出异常
     * @apiNote 仅管理员或用户本人可访问
     */
    @PostMapping("/update")
    @ApiOperation(value = "更新用户信息", notes = "更新用户详细信息，仅管理员或用户本人可访问")
    public Result<UserVO> updateUserById(@RequestBody UpdateUserDTO updateUserDTO, HttpServletRequest request) {
        // 非空判断
        if (ObjUtil.isEmpty(updateUserDTO)) {
            throw new BusinessException(ErrorCode.PRIMARY_ERROR);
        }
        // 仅当前用户或管理员可用
        User loginUser = userService.getLoginUser(request);
        if (!userService.isCompareRole(loginUser, UserRoleEnum.ADMIN.getKey()) && !loginUser.getId().equals(updateUserDTO.getId())) {
            throw new BusinessException(ErrorCode.NO_AUTH_ERROR, "仅管理员和自己可用");
        }
        UserVO userVO = userService.updateUser(updateUserDTO, request);
        return Result.success(userVO);
    }

    /**
     * 删除用户接口
     * @param id 要删除的用户ID
     * @param request HTTP请求对象，用于获取会话信息
     * @return 包含删除操作结果的Result对象
     * @throws BusinessException 如果用户无权限或存在外键约束会抛出异常
     * @apiNote 仅管理员可访问
     * @todo 删除教师用户时需检查外键约束
     */
    @DeleteMapping("/delete/{id}")
    @ApiOperation(value = "删除用户", notes = "根据用户ID删除用户，仅管理员可访问")
    public Result<Boolean> deleteUserById(@PathVariable("id") Integer id, HttpServletRequest request) {
        // 非空判断
        if (id == null) {
            throw new BusinessException(ErrorCode.PRIMARY_ERROR);
        }
        // 判断是否为管理员
        User loginUser = userService.getLoginUser(request);
        if (!userService.isCompareRole(loginUser, UserRoleEnum.ADMIN.getKey())) {
            throw new BusinessException(ErrorCode.NO_AUTH_ERROR, "仅管理员可用");
        }
        // 删除用户通过id
        Boolean res = userService.deleteUserById(id, request);
        return Result.success(res);
    }

    /**
     * 添加用户接口
     * @param addUserDTO 用户添加信息DTO，包含用户名、密码、角色等信息
     * @param request HTTP请求对象，用于获取会话信息
     * @return 包含新增用户基本信息的Result对象
     * @throws BusinessException 如果用户无权限或数据验证失败会抛出异常
     * @apiNote 仅管理员可访问
     */
    @PostMapping("/add")
    @ApiOperation(value = "添加新用户", notes = "添加一个新用户到系统，仅管理员可访问")
    public Result<UserVO> addUser(@RequestBody AddUserDTO addUserDTO, HttpServletRequest request) {
        // 非空判断
        if (addUserDTO == null) {
            throw new BusinessException(ErrorCode.PRIMARY_ERROR);
        }
        // 判断是否为管理员
        User loginUser = userService.getLoginUser(request);
        if (!userService.isCompareRole(loginUser, UserRoleEnum.ADMIN.getKey())) {
            throw new BusinessException(ErrorCode.NO_AUTH_ERROR, "仅管理员可用");
        }
        // 添加
        UserVO userVO = userService.addUser(addUserDTO, request);
        return Result.success(userVO);
    }

    /**
     * 根据班级ID获取用户列表接口
     * @param classId 班级ID
     * @param request HTTP请求对象，用于获取会话信息
     * @return 包含用户列表的Result对象
     * @throws BusinessException 如果班级ID为空或用户无权限会抛出异常
     * @apiNote 仅管理员和教师可访问
     */
    @GetMapping("/list/{id}")
    @ApiOperation(value = "获取班级用户列表", notes = "根据班级ID获取该班级下的所有用户列表，仅管理员和教师可访问")
    public Result<List<UserVO>> getUsersByClassId(@PathVariable("id") Integer classId, HttpServletRequest request) {
        // 非空判断
        if (ObjUtil.isEmpty(classId)) {
            throw new BusinessException(ErrorCode.PRIMARY_ERROR);
        }
        List<UserVO> userVOList =  userService.getUsersByClassId(classId,request);
        return Result.success(userVOList);
    }


    // todo 需要做权限校验，对用户调用接口权限进行同意校验，通过拦截器实现

}